iT邦幫忙

2025 iThome 鐵人賽

DAY 14
0
Modern Web

【網頁是什麼,能吃嗎】── 零基礎也能學會網頁製作系列 第 14

【Day 14】從存在,再到完整 ── Vue.js 實作篇

  • 分享至 

  • xImage
  •  

今日筆者將接續昨天的內容,為這個小遊戲增加更多的功能,使得它更加的完整。
此次所新增的內容包含:

  1. 每當使用者答完一題,將會產生新的題目
  2. 遊戲結束後有著最終分數的顯示

那麼就讓我們直接開始今日的內容吧!

建立「下一題」

首先先於主程式中建立一個變數 question_id,用於紀錄現在所進行到的題目編號,並於顯示結果時一併列出一個「下一題」按鈕,當按下時,題號便會增加,表示已經進行到了下一個題目:

<script setup>
const question_id = ref(1);

function nextQuestion() {
  question_id.value++;
  showResult.value = false;
}
</script>

<template>
  <h1>Calculator Game</h1>
  <p>Question {{ question_id }}: </p>
  <Question @answer="(ans) => correct_ans = ans"/>

  <!-- 為了畫面簡潔而暫時省略掉此部份的程式碼 -->
  
  <div id="result" v-if="showResult">
    <p v-if="isCorrect">Your answer is correct!</p>
    <p v-else>You've answered wrong, the correct result is {{ correct_ans }}</p>
    <button @click="nextQuestion">Next</button>
  </div>
  <p v-else>Click on the button to check your answer</p>
</template>

不過現在的程式有一個問題,那便是現在僅僅只有題號會變動,但題目仍然不會改變,為了解決這個問題,我們可以在 Question 子元件中先利用 props 將題號傳進去,並於其中使用 watcher 來根據變數的數值改變來呼叫更新題目用的函式:

<script setup>
import { ref, watch } from 'vue'

var props = defineProps({ id: Number })

const num1 = ref(Math.floor(Math.random() * 100))
const num2 = ref(Math.floor(Math.random() * 100))
var op_id = Math.floor(Math.random() * 10 % 4)
const op = ['+', '-', '*', '/']

function generate() {
  num1.value = Math.floor(Math.random() * 100);
  num2.value = Math.floor(Math.random() * 100);
  op_id = Math.floor(Math.random() * 10 % 4);

  emit('answer', calculate());
}

function calculate() {
  switch (op_id) {
    case 0:
      return num1.value + num2.value
    case 1:
      return num1.value - num2.value
    case 2:
      return num1.value * num2.value
    default:
      return Math.floor(num1.value / num2.value)
  }
}

const emit = defineEmits(['answer']);
emit('answer', calculate());
watch(() => props.id, () => { generate() })
</script>

不過,有以下兩點需要特別注意:

  1. 在使用watch() 來觀察 id 的值時,需要以 () => props.id 的方式表示,否則會出現錯誤 (網頁參考
  2. 除了原本的emit() 之外,我們也要在新題目生成時再次使用 emit() 將新答案傳給父函式,否則父函式所擁有的答案數值不會有所改變

顯示最後的分數

此部份非常的簡單,只需要建立兩個變數:score,用於紀錄分數,以及 showScore,讓程式知道要何時顯示最後分數就可以了。至於要什麼時候去更新他們的數值,前者可以新增在 ok 按鈕被按下時所呼叫的函式,那個函式正式用來判斷輸入內容是否相同,至於後者則放在 next 按鈕所呼叫的 nextQuestion,如果題目編號已經為10時,表示使用者已經回答完10個題目,也便是顯示分數的時刻了。
程式碼如下:

<script setup>
import { ref } from 'vue';
import Question from './components/Question.vue'

const player_ans = ref(Number);
const correct_ans = ref(Number);
const score = ref(0);

const question_id = ref(1);
const isCorrect = ref();
const showResult = ref(false);
const showScore = ref(false);

function onInput(e) { player_ans.value = e.target.value }
function getResult() {
  isCorrect.value = (player_ans.value == correct_ans.value);
  score.value += (isCorrect.value) * 10;
  player_ans.value = null;
  showResult.value = true
}
function nextQuestion() {
  if(question_id.value == 10) {
    showScore.value = true;
    return;
  }
  question_id.value++;
  showResult.value = false;
}
</script>

<template>
  <h1>Calculator Game</h1>
  <div id="score" v-if="showScore">
    <p>Congratulations! You've finished the game!</p>
    <p>Score: {{ score }} points</p>
  </div>
  <div v-else>
    <p>Question {{ question_id }}: </p>
    <Question :id="question_id" @answer="(ans) => correct_ans = ans"/>

    <div id="answer">
      <input type="number" id="player_ans" v-model="player_ans" placeholder="answer">
      <button v-if="!showResult" @click="getResult">OK</button>
      <button v-else @click="nextQuestion">Next</button>
    </div>

    <div id="result" v-if="showResult">
      <p v-if="isCorrect">Your answer is correct!</p>
      <p v-else>You've answered wrong, the correct result is {{ correct_ans }}</p>
    </div>
    <p v-else>Click on the button to check your answer</p>
  </div>

</template>

<style scoped></style>

上一篇
【Day 13】來製作計算小遊戲!── Vue.js 實作篇
下一篇
【Day 15】來做一個......登入系統?── Vue.js 實作篇
系列文
【網頁是什麼,能吃嗎】── 零基礎也能學會網頁製作24
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言